-- Core.lua (Plug & Play core: defaults, fonts, utils, DB + reset + side-fall prefs)
local ADDON, DFFT = ...

-- Crée le namespace addon si besoin
DFFT = DFFT or {}
DFFT.version = DFFT.version or "Plug&Play-1.2"

local DEFAULT_FONT_NAME = "Teko Bold"

-- #########################################################
-- SavedVariables (déclarées dans le .toc : DamageFilterFTDB)
-- #########################################################
-- ⚠️ NE PAS créer la table trop tôt : on utilise un proxy vers _G.DamageFilterFTDB
do
  local function __sv()
    _G.DamageFilterFTDB = _G.DamageFilterFTDB or {}
    return _G.DamageFilterFTDB
  end
  local DBProxy = setmetatable({}, {
    __index    = function(_, k) return __sv()[k] end,
    __newindex = function(_, k, v) __sv()[k] = v end,
    __pairs    = function(_) local t = __sv(); return next, t, nil end,
    __len      = function(_) local t = __sv(); return #t end,
  })
  DFFT.DB = DBProxy
end
local DB = DFFT.DB

-- Verrou anti-réassignation sauvage de DFFT.DB (on garde le proxy)
do
  local mt = getmetatable(DFFT) or {}
  local prev = mt.__newindex
  mt.__newindex = function(t, k, v)
    if k == "DB" then
      if DEFAULT_CHAT_FRAME then
        DEFAULT_CHAT_FRAME:AddMessage("|cffff5555DFFT|r: DFFT.DB 重新分配尝试已被忽略。")
        local stk = debugstack and debugstack(3, 6, 0) or "<无堆栈>"
        DEFAULT_CHAT_FRAME:AddMessage("|cffff8888堆栈|r: " .. (stk:gsub("\n", " ↩ "):sub(1, 220)))
      end
      return
    end
    if prev then return prev(t, k, v) end
    rawset(t, k, v)
  end
  setmetatable(DFFT, mt)
end

-- #########################################################
-- Ressources / Constantes
-- #########################################################
local FONT_DIR = "Interface\\AddOns\\DamageFilterFT\\Fonts\\"

-- Table des polices (sans "Teko Var")
DFFT.KNOWN_FONTS = {
  ["Teko Bold"]      = FONT_DIR .. "Teko-Bold.ttf",
  ["Teko Light"]     = FONT_DIR .. "Teko-Light.ttf",
  ["League Spartan"] = FONT_DIR .. "LeagueSpartan-VariableFont_wght.ttf",
  ["Russo One"]      = FONT_DIR .. "RussoOne.ttf",

  ["Bagel Fat One"]          = FONT_DIR .. "BagelFatOne-Regular.ttf",
  ["Bungee Hairline"]        = FONT_DIR .. "BungeeHairline-Regular.ttf",
  ["Cherry Bomb One"]        = FONT_DIR .. "CherryBombOne-Regular.ttf",
  ["Dongle Bold"]            = FONT_DIR .. "Dongle-Bold.ttf",
  ["Doto Rounded Bold"]      = FONT_DIR .. "Doto_Rounded-Bold.ttf",
  ["Gaegu Bold"]             = FONT_DIR .. "Gaegu-Bold.ttf",
  ["Outfit SemiBold"]        = FONT_DIR .. "Outfit-SemiBold.ttf",
  ["Permanent Marker"]       = FONT_DIR .. "PermanentMarker-Regular.ttf",
  ["Qahiri"]                 = FONT_DIR .. "Qahiri-Regular.ttf",
  ["Rubik Spray Paint"]      = FONT_DIR .. "RubikSprayPaint-Regular.ttf",
  ["Titan One"]              = FONT_DIR .. "TitanOne-Regular.ttf",
  ["Yanone Kaffeesatz Bold"] = FONT_DIR .. "YanoneKaffeesatz-Bold.ttf",
}

DFFT.SYMBOL_FONT = FONT_DIR .. "DamageSymbols.ttf"
DFFT.CRIT_GLYPH  = "\226\156\166" -- ✦

-- === LibSharedMedia hookup (optionnel si LSM présent) =======================
local LSM = LibStub and LibStub("LibSharedMedia-3.0", true)

-- Enregistre nos polices locales dans LSM (si dispo)
if LSM then
  for display, path in pairs(DFFT.KNOWN_FONTS) do
    if type(path) == "string" and path ~= "" then
      LSM:Register("font", display, path)
    end
  end
end

-- Teste si un "nom de police" est disponible (LSM OU interne)
local function _isFontNameAvailable(name)
  if not name or name == "" then return false end
  if LSM and LSM.Fetch and LSM:Fetch("font", name, true) then return true end
  if DFFT.KNOWN_FONTS[name] then return true end
  return false
end

-- Renvoie un chemin de police exploitable, en priorisant LSM quand dispo
function DFFT.ResolveFontPath(name)
  if LSM and name then
    local p = LSM:Fetch("font", name, true)
    if p then return p end
  end
  return (DFFT.KNOWN_FONTS[name or ""]) or (STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF")
end

-- Liste fusionnée : polices LSM + polices locales (sans doublons)
function DFFT.ListFonts()
  local list, seen = {}, {}
  if LSM and LSM.List then
    for _, n in ipairs(LSM:List("font") or {}) do
      if not seen[n] then table.insert(list, n); seen[n] = true end
    end
  end
  for n,_ in pairs(DFFT.KNOWN_FONTS) do
    if not seen[n] then table.insert(list, n); seen[n] = true end
  end
  table.sort(list)
  return list
end
-- ===========================================================================

-- ====== Color aliases & hot override (AJOUT) ======
-- But : éviter le retour au rouge/orange pendant les pulses crit (cible/nameplate)
-- en permettant un override temporaire "vert pomme" déclenché par Healer.
DFFT._colorAliases = DFFT._colorAliases or {}

local function _aliasSetRGB(t, rgb)
  if not t or not rgb then return end
  t[1], t[2], t[3] = rgb[1], rgb[2], rgb[3]
  t.r, t.g, t.b    = rgb[1], rgb[2], rgb[3]
end

function DFFT.MakeColorAlias(name, rgb)
  local t = DFFT._colorAliases[name]
  if not t then
    t = {}
    DFFT._colorAliases[name] = t
  end
  _aliasSetRGB(t, rgb or {1,1,1})
  DFFT[name] = t
  return t
end

-- Crée les constantes "vivantes" pour les teintes chaudes
DFFT.MakeColorAlias("ORANGE",   {1.00, 0.55, 0.00})
DFFT.MakeColorAlias("FIRE_RED", {1.00, 0.15, 0.05})

-- Quelques alias de secours si le moteur les lit par ces noms
if not DFFT.RED        then DFFT.MakeColorAlias("RED",        {1.00, 0.10, 0.10}) end
if not DFFT.RED2       then DFFT.MakeColorAlias("RED2",       {1.00, 0.20, 0.20}) end
if not DFFT.CRIT_RED   then DFFT.MakeColorAlias("CRIT_RED",   {1.00, 0.15, 0.05}) end
if not DFFT.CRIT_END   then DFFT.MakeColorAlias("CRIT_END",   {1.00, 0.15, 0.05}) end
if not DFFT.BIG_END    then DFFT.MakeColorAlias("BIG_END",    {1.00, 0.55, 0.00}) end
if not DFFT.ULTRA_END  then DFFT.MakeColorAlias("ULTRA_END",  {1.00, 0.15, 0.05}) end
if not DFFT.PULSE_END  then DFFT.MakeColorAlias("PULSE_END",  {1.00, 0.15, 0.05}) end
if not DFFT.TARGET_RED then DFFT.MakeColorAlias("TARGET_RED", {1.00, 0.15, 0.05}) end
if not DFFT.TARGET_ORANGE then DFFT.MakeColorAlias("TARGET_ORANGE", {1.00, 0.55, 0.00}) end
if not DFFT.NAMEPLATE_RED then DFFT.MakeColorAlias("NAMEPLATE_RED", {1.00, 0.15, 0.05}) end
if not DFFT.NAMEPLATE_ORANGE then DFFT.MakeColorAlias("NAMEPLATE_ORANGE", {1.00, 0.55, 0.00}) end
if not DFFT.TARGET_PULSE_END then DFFT.MakeColorAlias("TARGET_PULSE_END", {1.00, 0.15, 0.05}) end
if not DFFT.NAMEPLATE_PULSE_END then DFFT.MakeColorAlias("NAMEPLATE_PULSE_END", {1.00, 0.15, 0.05}) end

-- Override temporaire des couleurs "chaudes" (utilisé par Healer sur Big/Ultra)
DFFT._hotOverrideRef = 0
DFFT._hotOverrideSaved = nil

local function _isHotAliasName(name)
  return name:find("RED") or name:find("ORANGE") or name:find("PULSE") or name:find("END")
      or name:find("TARGET") or name:find("NAMEPLATE")
end

function DFFT.HotOverrideBegin(rgb)
  if not rgb then return end
  DFFT._hotOverrideRef = DFFT._hotOverrideRef + 1
  if DFFT._hotOverrideRef == 1 then
    DFFT._hotOverrideSaved = {}
    for name, alias in pairs(DFFT._colorAliases) do
      if _isHotAliasName(name) then
        DFFT._hotOverrideSaved[name] = { alias[1], alias[2], alias[3] }
        _aliasSetRGB(alias, rgb)
      end
    end
  else
    -- Si plusieurs heals Big/Ultra se chevauchent, on applique la dernière teinte demandée
    for name, alias in pairs(DFFT._colorAliases) do
      if _isHotAliasName(name) then
        _aliasSetRGB(alias, rgb)
      end
    end
  end
end

function DFFT.HotOverrideEnd()
  if DFFT._hotOverrideRef == 0 then return end
  DFFT._hotOverrideRef = DFFT._hotOverrideRef - 1
  if DFFT._hotOverrideRef == 0 and DFFT._hotOverrideSaved then
    for name, old in pairs(DFFT._hotOverrideSaved) do
      local alias = DFFT._colorAliases[name]
      if alias then _aliasSetRGB(alias, old) end
    end
    DFFT._hotOverrideSaved = nil
  end
end
-- ====== Fin du bloc alias/override (AJOUT) ======

-- (les deux constantes ci-dessous restent assignées pour compat, mais ce sont nos alias)
-- DFFT.ORANGE   = {1.00, 0.55, 0.00}
-- DFFT.FIRE_RED = {1.00, 0.15, 0.05}

-- #########################################################
-- Defaults (alignés plug & play)
-- #########################################################
DFFT.defaults = {
  -- visibilité
  showSmall   = true,
  showMedium  = true,

  -- ancrage global (tous tiers) : false => sur joueur, true => sur cible
  globalAnchorToTarget = true,

  -- player anchor horizontal spread
  playerSideSpread = 75,

  -- short format toujours actif (pas d’option UI)
  shortSmall  = true,
  shortMedium = true,

  -- 中文单位缩写选项
  useChineseUnits = false,

  -- seuils (seront écrasés si Auto actif)
  smallMax      = 200000,
  bigMin        = 900001,
  mediumMax     = 900000, -- compat legacy
  veryBigMin    = 10000000,

  -- couleurs
  smallColor    = {0.70, 0.70, 0.70},
  mediumColor   = {1.00, 1.00, 1.00},
  bigColor      = {1.00, 0.85, 0.00},
  veryBigColor  = {1.00, 0.55, 0.00},

  -- tailles / échelles
  smallScale    = 0.9,
  mediumScale   = 1.2,
  bigScaleBase  = 2.0,
  bigScaleMax   = 3.2,
  scaleCapAt    = 5000000,

  -- alpha
  smallAlpha    = 0.9,
  mediumAlpha   = 1.0,
  bigAlpha      = 1.0,
  veryBigAlpha  = 1.0,

  -- durées
  durationSmall  = 0.9,
  durationMedium = 1.0,
  durationBig    = 1.8,

  -- mouvement "rise" (par défaut)
  riseY = 80,
  diagHSmall   = -36,
  diagHMedium  = -44,
  diagHBig     = -56,
  diagHUltra   =  64,

  -- positions (fallback écran)
  smallAnchorX   = -54,  smallAnchorY   = -140,
  mediumAnchorX  = -24,  mediumAnchorY  = -132,
  bigAnchorX     =   0,  bigAnchorY     = -120,
  vbigAnchorX    =   0,  vbigAnchorY    = -118,

  -- offsets par tier (le choix target/joueur est global)
  smallTargetOffsetX  = 0, smallTargetOffsetY  = 28,
  mediumTargetOffsetX = 6, mediumTargetOffsetY = 34,
  bigTargetOffsetX    = 0, bigTargetOffsetY    = 40,
  vbigTargetOffsetX   = 0, vbigTargetOffsetY   = 48,

  -- jitter "rise"
  jitterX = 16,
  jitterY = 10,

  -- anti-overlap big/ultra
  antiOverlap     = true,
  antiOverlapPadY = 26,

  -- style non-cible
  nonTargetColor   = {0.51, 0.88, 1.00},
  nonTargetScale   = 0.85,
  nonTargetOffsetX = 120,
  nonTargetOffsetY = 16,

  -- ✅ anti-overlap dédié non-cible (bleus)
  nonTargetAntiOverlap   = true,
  nonTargetPadY          = 18,   -- empilement vertical minimum
  nonTargetScaleOverlap  = 0.70, -- −30% quand collés

  -- police (outline interne)
  fontName    = "Teko Bold",
  fontOutline = "OUTLINE",

  -- minimap
  minimap = { hide = false, pos = 220, icon = "Interface\\Icons\\Ability_CriticalStrike" },

  -- divers
  includePet = true,
  maxActive  = 20,
  hideDefaultCombatText = true,

  -- symboles/crit
  showCritSymbol = false,

  -- compensation hauteur nameplate cible
  targetHeightComp = 0.40,

  -- auto-thresholds (actif par défaut)
  autoThresholds = true,

  -- … (tes clés existantes)

  -- couleurs (répétées par compat)
  smallColor    = {0.70, 0.70, 0.70},
  mediumColor   = {1.00, 1.00, 1.00},
  bigColor      = {1.00, 0.85, 0.00},
  veryBigColor  = {1.00, 0.55, 0.00},
  -- ➕ par défaut pour les dégâts non-cible (bleu ciel)
  nonTargetColor = {0.45, 0.75, 1.00},

  -- Special effects (défauts)
  showCritSymbol      = false, -- étoile masquée par défaut
  UltraFXEnabled      = true,  -- explosions ON par défaut
  UltraFXGlintEnabled = true,  -- glint ON par défaut

  -- ========= Effets spéciaux =========
  enableShake = true,     -- UI flag
  shakeEnabled = true,    -- legacy flag (lu par l’animation)
  enableZoom  = true,     -- zoom / pulse

  -- ========= Prefs cachées : mode side-fall =========
  sideFallEnabled   = true,   -- active le mode latéral quand la plate est tout en haut
  sideFallTopRatio  = 0.92,   -- déclenchement : TOP(plate)/UIParent:Height >= ratio
  sideLaneSpacing   = 28,     -- espacement vertical entre "voies"
  sideJitterX       = 8,      -- jitter latéral faible
  sideJitterY       = 6,      -- jitter vertical faible

  -- offsets latéraux (en px) relatifs au TOP de la plate
  sideLeftSmall   =  -90,
  sideLeftMedium  = -130,
  sideLeftBig     = -170,
  sideRightUltra  =  110,     -- Ultra à droite

  -- paramètres de chute (balistique simplifiée)
  fallGravity     = 520,      -- px/s^2 (vers le bas)
  fallInitialVY   = -24,      -- px/s (léger "hop" vers le haut au départ => négatif)
  fallVXSmall     = 260,      -- px/s latéral
  fallVXMedium    = 240,
  fallVXBig       = 220,
  fallVXUltra     = 260,

  -- ====== Nouveau : préférence claire pour l'ancrage non-cible ======
  -- Quand true et que globalAnchorToTarget == true, les dégâts non-cible
  -- s’ancrent aussi sur la nameplate de la cible (colonne droite).
  nonTargetAnchorFollowsTarget = true,

  lastExport = "",
}

-- #########################################################
-- Helpers d'ancrage (nouveau, rétro-compat)
-- #########################################################
function DFFT.ShouldAnchorToTarget()
  return DB.globalAnchorToTarget == true
end

function DFFT.ShouldNonTargetFollowTarget()
  -- suit la cible si globalAnchorToTarget et si la préférence n'est pas explicitement false
  if not DFFT.ShouldAnchorToTarget() then return false end
  if DB.nonTargetAnchorFollowsTarget == nil then return true end
  return DB.nonTargetAnchorFollowsTarget ~= false
end

-- Retourne "TARGET" ou "PLAYER" selon le type d'évènement
-- isTarget: événement sur la cible actuelle
-- isNonTarget: événement sur une autre cible (bleu)
function DFFT.PickAnchor(isTarget, isNonTarget)
  if isTarget then return "TARGET" end
  if isNonTarget then
    if DFFT.ShouldNonTargetFollowTarget() then
      return "TARGET"
    else
      return "PLAYER"
    end
  end
  -- Par défaut : respect du global
  return DFFT.ShouldAnchorToTarget() and "TARGET" or "PLAYER"
end

-- Fournit les offsets par tier selon l’ancrage choisi, pour centraliser la logique
function DFFT.GetTierOffsets(tier, isTarget, isNonTarget)
  local anchor = DFFT.PickAnchor(isTarget, isNonTarget)
  if anchor == "TARGET" then
    if tier == "small"  then return DB.smallTargetOffsetX or 0,  DB.smallTargetOffsetY  or 28 end
    if tier == "medium" then return DB.mediumTargetOffsetX or 6, DB.mediumTargetOffsetY or 34 end
    if tier == "big"    then return DB.bigTargetOffsetX or 0,    DB.bigTargetOffsetY    or 40 end
    if tier == "vbig"   then return DB.vbigTargetOffsetX or 0,   DB.vbigTargetOffsetY   or 48 end
  end
  -- fallback joueur (ancres écran)
  if tier == "small"  then return DB.smallAnchorX or -54,   DB.smallAnchorY  or -140 end
  if tier == "medium" then return DB.mediumAnchorX or -24,  DB.mediumAnchorY or -132 end
  if tier == "big"    then return DB.bigAnchorX or 0,       DB.bigAnchorY    or -120 end
  if tier == "vbig"   then return DB.vbigAnchorX or 0,      DB.vbigAnchorY   or -118 end
  return 0, 0
end

-- #########################################################
-- Utils exportés (utilisés par d’autres fichiers)
-- #########################################################
local function pathForFont(name)
  if DFFT and DFFT.ResolveFontPath then
    return DFFT.ResolveFontPath(name)
  end
  return DFFT.KNOWN_FONTS[name or ""] or DFFT.KNOWN_FONTS["Teko Bold"]
end

function DFFT.ensureFont(fs, px, outline)
  local file = pathForFont(DB.fontName)
  local ok = fs:SetFont(file, px or 30, outline or (DB.fontOutline or "OUTLINE"))
  if not ok then
    fs:SetFont(STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF", px or 30, outline or (DB.fontOutline or "OUTLINE"))
  end
end

function DFFT.rgb(col)
  if not col then return 1,1,1 end
  return col[1] or 1, col[2] or 1, col[3] or 1
end

function DFFT.clamp(x,a,b)
  if x < a then return a elseif x > b then return b else return x end
end

function DFFT.mapLinear(x,inMin,inMax,outMin,outMax)
  if inMax <= inMin then return outMax end
  local t=(x-inMin)/(inMax-inMin)
  if t<0 then t=0 elseif t>1 then t=1 end
  return outMin + (outMax - outMin) * t
end

function DFFT.shortNumber(n)
  if DB.useChineseUnits then
    -- 中文单位缩写：万、亿
    if n >= 100000000 then  -- 1亿
      local x = math.floor((n/100000000)*10 + 0.5) / 10
      local s = tostring(x):gsub("%.0$","")
      return s .. "亿"
    elseif n >= 10000 then  -- 1万
      local x = math.floor((n/10000)*10 + 0.5) / 10
      local s = tostring(x):gsub("%.0$","")
      return s .. "万"
    else
      return tostring(n)
    end
  else
    -- 原版西方单位缩写：K、M、B
    if n >= 1000000000 then
      local x = math.floor((n/1000000000)*10 + 0.5) / 10
      local s = tostring(x):gsub("%.0$","")
      return s .. "B"
    elseif n >= 1000000 then
      local x = math.floor((n/1000000)*10 + 0.5) / 10
      local s = tostring(x):gsub("%.0$","")
      return s .. "M"
    elseif n >= 1000 then
      return tostring(math.floor((n + 500)/1000)) .. "K"
    else
      return tostring(n)
    end
  end
end

function DFFT.shortNumberRounded(n)
  if DB.useChineseUnits then
    -- 中文单位缩写版本
    if n >= 100000000 then  -- 1亿
      return DFFT.shortNumber(n)
    elseif n >= 10000 then  -- 1万
      return tostring(math.floor((n + 5000)/10000)) .. "万"
    else
      return tostring(n)
    end
  else
    -- 原版西方单位缩写
    if n >= 1000000 then
      return DFFT.shortNumber(n)
    elseif n >= 1000 then
      return tostring(math.floor((n + 500)/1000)) .. "K"
    else
      return tostring(n)
    end
  end
end

function DFFT.ApplyDefaultCombatTextSetting()
  local hide = DB.hideDefaultCombatText and "0" or "1"
  if C_CVar and C_CVar.SetCVar then
    C_CVar.SetCVar("floatingCombatTextCombatDamage", hide)
    C_CVar.SetCVar("floatingCombatTextDamageReduction", hide)
  end
end

-- #########################################################
-- Defaults / Reset
-- #########################################################
local function deepcopy(src)
  if type(src) ~= "table" then return src end
  local t = {}
  for k,v in pairs(src) do t[k] = deepcopy(v) end
  return t
end

function DFFT.ApplyDefaults()
  local defs = DFFT.defaults
  -- compat ancienne clé mediumMax -> bigMin
  if DB.bigMin == nil and DB.mediumMax ~= nil then
    DB.bigMin = (DB.mediumMax or defs.mediumMax) + 1
  end
  -- injecte les valeurs manquantes
  for k,v in pairs(defs) do
    if DB[k] == nil then DB[k] = deepcopy(v) end
  end
  -- garde-fous seuils
  if DB.smallMax >= DB.bigMin then
    DB.bigMin = DB.smallMax + 1
  end
  if DB.veryBigMin <= DB.bigMin then
    DB.veryBigMin = DB.bigMin + 1
  end
  -- minimap table sûre
  if type(DB.minimap) ~= "table" then
    DB.minimap = deepcopy(defs.minimap)
  else
    if DB.minimap.pos == nil then DB.minimap.pos = 220 end
    if DB.minimap.hide == nil then DB.minimap.hide = false end
    if not DB.minimap.icon then DB.minimap.icon = defs.minimap.icon end
  end
  -- force short formats activés (pas d’options UI)
  DB.shortSmall  = true
  DB.shortMedium = true

  -- map legacy flags
  if DB.enableShake == false then DB.shakeEnabled = false end

  -- --- Font bootstrap: force Teko Bold au premier run / si valeur invalide ---
  if not DB._fontBootstrapped then
    if not _isFontNameAvailable(DB.fontName) then
      DB.fontName = DEFAULT_FONT_NAME
    end
    DB._fontBootstrapped = true
  end

  -- ====== Bootstrap ancrage non-cible ======
  -- Si l’utilisateur force l’ancrage global sur la cible et que la préférence n’a
  -- jamais été définie, on s’assure que les non-cibles suivent la cible (droite).
  if DB.globalAnchorToTarget == true and DB.nonTargetAnchorFollowsTarget == nil then
    DB.nonTargetAnchorFollowsTarget = true
  end

  -- applique CVar
  DFFT.ApplyDefaultCombatTextSetting()

  -- refresh immédiat des fontes actives si le moteur a déjà créé des frames
  if type(DFFT.refreshActiveFonts) == "function" then
    pcall(DFFT.refreshActiveFonts)
  end
end

function DFFT.ResetAll()
  -- Remet intégralement la DB aux defaults
  for k in pairs(DB) do DB[k] = nil end
  for k,v in pairs(DFFT.defaults) do DB[k] = deepcopy(v) end
  DFFT.ApplyDefaults()
  -- Sème les seuils si l’auto est dispo/actif
  if DB.autoThresholds and DFFT.Auto_InitSeed then
    DFFT.Auto_InitSeed()
  end
  print("|cffffd100DFFT:|r 默认设置已恢复。")
end

function DFFT.SetCritColorFadeEnabled(on)
  DB.enableCritColorFade = not not on
end

-- #########################################################
-- Init au chargement
-- #########################################################
local initFrame = CreateFrame("Frame")
initFrame:RegisterEvent("ADDON_LOADED")
initFrame:RegisterEvent("PLAYER_LOGIN")
initFrame:SetScript("OnEvent", function(_, event, arg1)
  if event == "ADDON_LOADED" and arg1 == ADDON then
    DFFT.ApplyDefaults()
    if DB.autoThresholds and DFFT.Auto_InitSeed then
      DFFT.Auto_InitSeed()
    end
  elseif event == "PLAYER_LOGIN" then
    DFFT.ApplyDefaults()
  end
end)
